package org.dsbackend.security.controller;

import java.util.HashMap;
import java.util.Objects;
import javax.servlet.http.HttpServletRequest;

import org.dsbackend.entity.ResultException;
import org.dsbackend.entity.JsonData;
import org.dsbackend.security.JwtToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.web.bind.annotation.*;
import org.dsbackend.security.JwtTokenUtil;
import org.dsbackend.security.JwtUser;
import org.dsbackend.security.service.JwtAuthenticationResponse;

@RestController
@RequestMapping("${jwt.route.authentication.path}")
public class AuthenticationRestController {

    @Value("${jwt.header}")
    private String tokenHeader;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    @Qualifier("jwtUserDetailsService")
    private UserDetailsService userDetailsService;

    @RequestMapping(value = "${jwt.route.authentication.login}", method = RequestMethod.POST)
    public JsonData createAuthenticationToken(@RequestParam(value = "username") String username
        ,@RequestParam(value = "password") String password) throws AuthenticationException {

        authenticate(username, password);

        final UserDetails userDetails = userDetailsService.loadUserByUsername(username);
        final String token = jwtTokenUtil.generateToken(userDetails);

        HashMap return_data=new HashMap();
        return_data.put("username",userDetails.getUsername());
        return_data.put("userType",userDetails.getAuthorities().toArray()[0].toString());
        return_data.put("token",token);

        return new JsonData(0,"succeess",return_data);
    }

    @RequestMapping(value = "${jwt.route.authentication.refresh}", method = RequestMethod.GET)
    public JsonData refreshAndGetAuthenticationToken(HttpServletRequest request) {
        String token = request.getHeader(tokenHeader);
        String username = jwtTokenUtil.getUsernameFromToken(token);
        JwtUser user = (JwtUser) userDetailsService.loadUserByUsername(username);

        if (jwtTokenUtil.canTokenBeRefreshed(token, user.getLastPasswordResetDate())) {
            String refreshedToken = jwtTokenUtil.refreshToken(token);
            return new JsonData(0,"succeess",new JwtAuthenticationResponse(refreshedToken));
        } else {
            throw new ResultException(401,"");
        }
    }

    @RequestMapping(value = "${jwt.route.authentication.info}", method = RequestMethod.GET)
    public JsonData getAuthenticationTokenInfo(HttpServletRequest request) {
        String token = request.getHeader(tokenHeader);
        return new JsonData(0,"succeess",new JwtToken(jwtTokenUtil.getUsernameFromToken(token)
            ,jwtTokenUtil.getExpirationDateFromToken(token)));
    }

    private void authenticate(String username, String password) {
        Objects.requireNonNull(username);
        Objects.requireNonNull(password);

        try {
            authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
        } catch (DisabledException e) {
            throw new ResultException(402,"system error");
        } catch (BadCredentialsException e) {
            throw new ResultException(401,"username or password is incorrect");
        }
    }
}
